package com.lovesher.payment.service.plugin.alipay;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.lovesher.payment.common.enums.NotifyMethod;
import com.lovesher.payment.common.enums.PayStatus;
import com.lovesher.payment.common.resposity.bean.AccountRechargeDTO;
import com.lovesher.payment.common.resposity.bean.PaymentSerial;
import com.lovesher.payment.common.resposity.bean.PluginConfig;
import com.lovesher.payment.common.resposity.bean.PluginConfigAttribute;
import com.lovesher.payment.service.resposity.bean.PaymentInterface;
import com.lovesher.payment.service.resposity.dao.PaymentDao;
import com.lovesher.payment.service.resposity.dao.PaymentSerialDao;
import com.lovesher.payment.service.resposity.mapper.PluginConfigAttributeMapper;

/**
 * @Title: aliRefundplugin.java
 * @Description: 支付宝退款插件
 * @version V1.0
 */
@Component("aliRefundPlugin")
public class AliRefundPlugin extends PaymentInterface {

	private static Log log = LogFactory.getLog(AliRefundPlugin.class);

	@Resource
	private PluginConfigAttributeMapper pluginConfigAttributeMapper;
	@Resource
	private PaymentDao paymentDao;
	@Resource
	private PaymentSerialDao paymentSerialDao;

	private final String reqUrl = "https://openapi.alipay.com/gateway.do";
	
	@Override
	public String getName() {
		return "支付宝支付";
	}

	@Override
	public String getVersion() {
		return "1.0";
	}

	@Override
	public String getAuthor() {
		return "tupx";
	}

	/**
	 * 获取网址
	 * 
	 * @return 网址
	 */
	@Override
	public String getSiteUrl() {
		return "https://doc.open.alipay.com";
	}

	/**
	 * 获取请求URL
	 * 
	 * @return 请求URL
	 */
	@Override
	public String getRequestUrl() {
		return reqUrl;
	}

	/**
	 * 获取请求方法
	 * 
	 * @return 请求方法
	 */
	@Override
	public RequestMethod getRequestMethod() {
		return RequestMethod.post;
	}

	/**
	 * 获取请求字符编码
	 * 
	 * @return 请求字符编码
	 */
	@Override
	public String getRequestCharset() {
		return "UTF-8".toLowerCase();
	}

	/**
	 * 是否需要新增查询任务
	 */
	@Override
	public boolean getIsQueryTask() {
		return true;
	}

	/**
	 * 使用 Map按key进行排序
	 * 
	 * @param map
	 * @return
	 */
	public static Map<String, Object> sortMapByKey(Map<String, String> map) {
		if (map == null || map.isEmpty()) {
			return null;
		}

		Map<String, Object> sortMap = new TreeMap<String, Object>();

		sortMap.putAll(map);

		return sortMap;
	}

	/**
	 * @param serialSn 为之前的充值我们平台的流水号
	 * @param accountRechargeDTO.getOrderSn() 是退款流水号
	 * 
	 * @param accountRechargeDTO.getMoney() 是充值的金额 单位元
	 * 
	 * @param accountRechargeDTO.getFee() 退款总金额，单位元
	 * 
	 * @param accountRechargeDTO.getRemark()  若商户传入，会在下发给用户的退款消息中体现退款原因
	 * 
	 */
	@Override
	public Map<String, String> getParameterMap(AccountRechargeDTO accountRechargeDTO, String serialSn) {
		PluginConfig pluginConfig = getPluginConfig();
		// 数据库中获取支付相关参数
		Map<String, Object> pluginConfigMap = getPluginConfigMap(pluginConfig);
		log.info("【订单退款:" + serialSn + "userId" + accountRechargeDTO.getUserId() + "】开始封装参数...");
		String appId = pluginConfigMap.get("app_id").toString();
		String charset = this.getRequestCharset();
		String signType = pluginConfigMap.get("sign_type").toString();
		String privateKey = pluginConfigMap.get("private_key").toString();
		String publicKey = pluginConfigMap.get("alipay_public_key").toString();
	
		AlipayClient alipayClient = new DefaultAlipayClient(getRequestUrl(), appId, privateKey, AlipayConfig.FORMAT,
				charset, publicKey, signType);
		AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
		AlipayTradeRefundModel model = new AlipayTradeRefundModel();
		model.setRefundAmount(accountRechargeDTO.getFee().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
		model.setRefundReason(accountRechargeDTO.getRemark());
		model.setOutTradeNo(serialSn);
		model.setOutRequestNo(accountRechargeDTO.getOrderSn());
		request.setBizModel(model);
		try{
			Map<String, String> resultMap = new HashMap<String, String>();
			AlipayTradeRefundResponse response = alipayClient.execute(request);
			log.info(JSON.toJSONString(response));
			if(response.isSuccess() && response.getFundChange().equalsIgnoreCase("Y") && null != response.getRefundFee()){
				resultMap.put("success", Boolean.TRUE.toString());
				resultMap.put("message", response.getMsg());
			} else if(response.isSuccess() && response.getFundChange().equalsIgnoreCase("N") && null != response.getRefundFee()){
				resultMap.put("success", Boolean.TRUE.toString());
				resultMap.put("message", response.getMsg());
			}else{
				resultMap.put("success", Boolean.FALSE.toString());
				resultMap.put("message", response.getMsg());
			}
			return resultMap;
		}catch(Exception e){
			log.error("【订单退款:" + serialSn + "userId" + accountRechargeDTO.getUserId() + "】...",e);
		}
		return null;
	}

	/**
	 */
	private Map<String, Object> getPluginConfigMap(PluginConfig pluginConfig) {
		Map<String, Object> pluginConfigMap = new HashMap<String, Object>();
		List<PluginConfigAttribute> pluginConfigAttributes = pluginConfigAttributeMapper
				.findByPluginId(pluginConfig.getId());
		for (int i = 0; i < pluginConfigAttributes.size(); i++) {
			PluginConfigAttribute pluginConfigAttribute = pluginConfigAttributes.get(i);
			pluginConfigMap.put(pluginConfigAttribute.getName(), pluginConfigAttribute.getAttributes());
		}
		return pluginConfigMap;
	}

	/**
	 * 构造签名
	 * 
	 * @param params
	 * @param pluginConfigMap
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public String createSign(Map<String, String> params, Map<String, Object> pluginConfigMap) {
		return AliRSA.sign(params, pluginConfigMap.get("private_key").toString(), this.getRequestCharset());
	}

	/**
	 * 验证通知是否合法
	 * 
	 * @param sn
	 *            编号
	 * @param notifyMethod
	 *            通知方法
	 * @param request
	 *            httpServletRequest
	 * @return 通知是否合法
	 */
	@Override
	public Map<String, Object> verifyNotify(String sn, NotifyMethod notifyMethod, HttpServletRequest request,
			PaymentSerial paymentSerial) {
		Map<String, Object> returnNotify = new HashMap<String, Object>();
		returnNotify.put("success", true);
		returnNotify.put("returnText", "验签成功");
		return returnNotify;
	}

	/**
	 * 获取通知返回消息
	 * 
	 * @param sn
	 *            编号
	 * @param notifyMethod
	 *            通知方法
	 * @param request
	 *            httpServletRequest
	 * @return 通知返回消息
	 */
	@Override
	public String getNotifyMessage(String sn, NotifyMethod notifyMethod, HttpServletRequest request) {
		if (notifyMethod == NotifyMethod.async) {
			return "success";
		}
		return "failure";
	}

	/**
	 * 获取超时时间
	 * 
	 * @return 超时时间
	 */
	@Override
	public Integer getTimeout() {
		return 21600;
	}

	/**
	 * 充值支付回调验证成功处理方法
	 * 
	 * @param request
	 */
	@Override
	public void paySucess(PaymentSerial paymentSerial, String returnText, PayStatus payStatus,
			HttpServletRequest request) {
		
	}

	@Override
	public Boolean queryOrderResult(PaymentSerial paymentSerial) {
		// 根据充值流水号查询支付状态
		if (null != paymentSerial && paymentSerial.getStatus() == PayStatus.INIT.getValue()) {
			PluginConfig pluginConfig = getPluginConfig();
			// 数据库中获取支付相关参数
			Map<String, Object> pluginConfigMap = getPluginConfigMap(pluginConfig);
			log.info("【订单退款查询:" + paymentSerial.getOrderSn() + "userId" + paymentSerial.getUserId() + "】开始封装参数...");
			String appId = pluginConfigMap.get("app_id").toString();
			String charset = this.getRequestCharset();
			String signType = pluginConfigMap.get("sign_type").toString();
			String privateKey = pluginConfigMap.get("private_key").toString();
			String publicKey = pluginConfigMap.get("alipay_public_key").toString();

			AlipayClient client = new DefaultAlipayClient(getRequestUrl(), appId, privateKey, AlipayConfig.FORMAT,
					charset, publicKey, signType);
			AlipayTradeFastpayRefundQueryRequest alipay_request = new AlipayTradeFastpayRefundQueryRequest();
			AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel();
			model.setOutTradeNo(paymentSerial.getTradeNo());//订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 
			model.setOutRequestNo(paymentSerial.getOrderSn());//请求退款接口时，传入的退款请求号，如果在退款请求时未传入，则该值为创建交易时的外部交易号
			alipay_request.setBizModel(model);

			try {
				AlipayTradeFastpayRefundQueryResponse response = client.execute(alipay_request);
				log.info(JSON.toJSONString(response));
				if (response.isSuccess()) {
					if(response.getCode().equalsIgnoreCase("10000") && null != response.getRefundAmount()){
						return true;
					}
				}
			} catch (AlipayApiException e) {
				log.error(e.getMessage(), e);
				return false;
			}
		}
		return false;
	}

}
